// -----------------------------------------------------------------------
//  <copyright file="ModuleBase.cs" company="LiuliuSoft">
//      Copyright (c) 2022-2022 DaprPlus. All rights reserved.
//  </copyright>
//  <site>https://www.dapr.plus</site>
//  <last-editor>郭明锋</last-editor>
//  <last-date>2022-11-17 0:20</last-date>
// -----------------------------------------------------------------------

namespace DaprPlus.Builder;

/// <summary>
/// DaprPlus模块基类
/// </summary>
public abstract class ModuleBase
{
    /// <summary>
    /// 获取 模块所在程序集信息
    /// </summary>
    public virtual Assembly Assembly => GetType().Assembly;

    /// <summary>
    /// 获取 模块级别，级别越小越先启动
    /// </summary>
    public virtual ModuleLevel Level => ModuleLevel.Business;

    /// <summary>
    /// 获取 模块启动顺序，模块启动的顺序按级别启动，同一级别内部再按此顺序启动
    /// 级别默认为0，表示无依赖，需要在同级别有依赖顺序的时候，再重写为>0的顺序值
    /// </summary>
    public virtual int Order => 0;

    /// <summary>
    /// 获取 是否已可用
    /// </summary>
    public bool IsEnabled { get; protected set; }

    /// <summary>
    /// 将模块服务添加到依赖注入服务容器中
    /// </summary>
    /// <param name="services">依赖注入服务容器</param>
    /// <returns></returns>
    public virtual IServiceCollection AddServices(IServiceCollection services)
    {
        return services;
    }

    /// <summary>
    /// 应用模块服务
    /// </summary>
    /// <param name="provider">服务提供者</param>
    public virtual Task UseModule(IServiceProvider provider)
    {
        IsEnabled = true;
        return Task.CompletedTask;
    }

    /// <summary>
    /// 获取当前模块的依赖模块类型
    /// </summary>
    /// <returns></returns>
    internal Type[] GetDependedModuleTypes()
    {
        var moduleType = GetType();
        var stack = new Stack<Type>(new[] { moduleType });
        var dependTypes = new List<Type>();
        while (stack.Count > 0)
        {
            var tmpType = stack.Pop();
            var dependAttrs = tmpType.GetAttributes<DependsOnModulesAttribute>();
            if (dependAttrs.Length == 0)
            {
                continue;
            }

            foreach (var dependAttr in dependAttrs)
            {
                var moduleTypes = dependAttr.DependedModuleTypes;
                if (moduleTypes.Length == 0)
                {
                    continue;
                }

                dependTypes.AddRange(moduleTypes);
                foreach (var type in moduleTypes)
                {
                    stack.Push(type);
                }
            }
        }

        return dependTypes.Distinct().ToArray();
    }

    internal string GetDisplay()
    {
        var type = GetType();
        var desc = type.GetDescription();
        return $"{desc}[{type.FullName}]";
    }
}
